package com.sunday.common.core.gson;

import com.google.gson.Gson;
import com.sunday.common.core.utils.DateTimeUtils;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Json辅助解析类
 *
 * @author zsy
 * @since 2022/10/13
 */
public class ParamsParser implements Serializable {

    //核心请求参数
    private final LinkedHashMap<String, Object> documentAsMap;

    public ParamsParser() {
        documentAsMap = new LinkedHashMap<>();
    }

    public ParamsParser(final String key, final Object value) {
        documentAsMap = new LinkedHashMap<>();
        documentAsMap.put(key, value);
    }

    public ParamsParser(final Map<String, Object> map) {
        documentAsMap = new LinkedHashMap<>(map);
    }

    /**
     * json 转换 ParamsParser 对象
     */
    public static ParamsParser parse(final String json) {
        return parse(json, GsonUtils.DEFAULT);
    }

    private static ParamsParser parse(final String json, final Gson decoder) {
        assert json != null : "json must not be null";
        assert decoder != null : "decoder must not be null";
        return new ParamsParser(decoder.fromJson(json, Map.class));
    }

    /**
     * key 新增key
     * value 新增key value值
     */
    public ParamsParser append(final String key, final Object value) {
        documentAsMap.put(key, value);
        return this;
    }

    /**
     * 注意事项：类型必须绝对匹配才能采用此种方法,否则异常
     * key 检索key
     * clazz 返回类型泛型
     */
    public <T> T get(final String key, final Class<T> clazz) {
        assert clazz != null : "clazz must not be null";
        return (T) documentAsMap.get(key);
    }

    /**
     * 注意事项：类型必须绝对匹配才能采用此种方法,否则异常
     * key 检索key
     * defaultValue 如果获取值不存在  使用默认值
     */
    @SuppressWarnings("unchecked")
    public <T> T get(final String key, final T defaultValue) {
        assert defaultValue != null : "defaultValue must not be null";
        return documentAsMap.get(key) == null ? defaultValue : (T) documentAsMap.get(key);
    }

    public Integer getInteger(final String key) {
        assert get(key) != null : "key must not be null";
        return Integer.valueOf(key);
    }

    public Long getLong(final String key) {
        assert get(key) != null : "key must not be null";
        return Long.valueOf(key);
    }

    public Double getDouble(final String key) {
        assert get(key) != null : "key must not be null";
        return Double.valueOf(key);
    }

    public String getString(final String key) {
        assert get(key) != null : "key must not be null";
        return String.valueOf(get(key));
    }

    public Boolean getBoolean(final String key) {
        assert get(key) != null : "key must not be null";
        return Boolean.valueOf(key);
    }

    public LocalDateTime getLocalDateTime(final String key) {
        assert get(key) != null : "key must not be null";
        String dateTime = String.valueOf(get(key));
        return LocalDateTime.parse(dateTime, DateTimeUtils.dateTimeFormatAdapter(dateTime));
    }

    public int size() {
        return documentAsMap.size();
    }

    public boolean isEmpty() {
        return documentAsMap.isEmpty();
    }

    public boolean containsKey(final Object key) {
        return documentAsMap.containsKey(key);
    }

    public boolean containsValue(final Object value) {
        return documentAsMap.containsValue(value);
    }

    public Object get(final Object key) {
        return documentAsMap.get(key);
    }

    public Object put(final String key, final Object value) {
        return documentAsMap.put(key, value);
    }

    public Object remove(final Object key) {
        return documentAsMap.remove(key);
    }

    public void putAll(final Map<? extends String, ? extends Object> map) {
        documentAsMap.putAll(map);
    }

    public void clear() {
        documentAsMap.clear();

    }

    public Set<String> keySet() {
        return documentAsMap.keySet();
    }

    public Collection<Object> values() {
        return documentAsMap.values();
    }

    public Set<Map.Entry<String, Object>> entrySet() {
        return documentAsMap.entrySet();
    }

    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        ParamsParser document = (ParamsParser) o;

        if (!documentAsMap.equals(document.documentAsMap)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        return documentAsMap.hashCode();
    }

    @Override
    public String toString() {
        return new Gson().toJson(documentAsMap);
    }

}
